package Triangulation.minimalityMetrics;

import static tools.Tool.quadIsConvex;
import datatypes.Edge;
import datatypes.Triangle;

public class DelaunayMetric extends AbstractMinimalityMetric {
	
	private double smallestAngle(Triangle t) {
		
		double edgeLengthsT[] = new double[3];
		
		edgeLengthsT[0] = t.getEdge1().getLength();
		edgeLengthsT[1] = t.getEdge2().getLength();
		edgeLengthsT[2] = t.getEdge3().getLength();
		
		// law of cosines
		double a = Math.toDegrees(Math.acos((Math.pow(edgeLengthsT[1],2)+Math.pow(edgeLengthsT[2],2)-Math.pow(edgeLengthsT[0],2))/(2*edgeLengthsT[1]*edgeLengthsT[2])));
		double b = Math.toDegrees(Math.acos((Math.pow(edgeLengthsT[0],2)+Math.pow(edgeLengthsT[2],2)-Math.pow(edgeLengthsT[1],2))/(2*edgeLengthsT[0]*edgeLengthsT[2])));
		double c = Math.toDegrees(Math.acos((Math.pow(edgeLengthsT[0],2)+Math.pow(edgeLengthsT[1],2)-Math.pow(edgeLengthsT[2],2))/(2*edgeLengthsT[0]*edgeLengthsT[1])));
		
		return ((a < b ? a : b) < c ? (a < b ? a : b) : c);
	}
	
	public boolean edgeIsLocallyMinimal(Edge sharedEdge, Triangle t1, Triangle t2) {
		if ( ! quadIsConvex(t1, t2, sharedEdge)) {
			// If quad is NOT convex, then sharedEdge is locally minimal.
			// See "A Large Subgraph of the Minimum Weight Triangulation" 
			// p.291, 1.3
			return true;
		}
		
		double smallestAngleExistingQuad = (smallestAngle(t1) < smallestAngle(t2) ? smallestAngle(t1) : smallestAngle(t2));
		
		Edge perpendicular = new Edge(t1.getVertexNotOnEdge(sharedEdge), t2.getVertexNotOnEdge(sharedEdge));
		Edge e2t1 = new Edge(perpendicular.getVertex1(), sharedEdge.getVertex1());
		Edge e3t1 = new Edge(perpendicular.getVertex2(), sharedEdge.getVertex1());
		Edge e2t2 = new Edge(perpendicular.getVertex1(), sharedEdge.getVertex2());
		Edge e3t2 = new Edge(perpendicular.getVertex2(), sharedEdge.getVertex2());
		
		try {
			t1 = new Triangle(perpendicular, e2t1, e3t1, false);
			t2 = new Triangle(perpendicular, e2t2, e3t2, false);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		double smallestAngleFlippedQuad = (smallestAngle(t1) < smallestAngle(t2) ? smallestAngle(t1) : smallestAngle(t2));
		
		//System.out.println("Old: "+smallestAngleExistingQuad+"\nNew: "+smallestAngleFlippedQuad);
		return smallestAngleExistingQuad >= smallestAngleFlippedQuad;
	}
	
	@Override
	public double getAngleForDiamondProperty() {
		// diamond property applicable with beta = pi/4
		return Math.PI/4;
	}

	@Override
	public String getName() {
		return "delaunay";
	}

}